/*
 * FSWUniCEUB - 2008
 * 
 * Este arquivo é de propriedade da Fábrica de Software do UniCEUB
 * 
 * Para mais informações entre em contato com a coordenação do
 * curso de Ciência da Computação da instituição.
 */

package br.uniceub.fsw.seguranca.facade;

import br.uniceub.fsw.arquitetura.persistencia.transacao.Transacao;
import br.uniceub.fsw.seguranca.dao.ModuloDAO;
import br.uniceub.fsw.seguranca.vo.ModuloVO;
import br.uniceub.fsw.util.MontadorHtml;
import br.uniceub.fsw.util.TabelaHtml;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Facade da entidade Modulo.
 * 
 * @author Bruno Schifer Bernardi
 */
public class ModuloFacade {
    /**
     * Mensagem de retorno do sistema.
     */
    private String message;

    /**
     * Value object do modulo.
     */
    private ModuloVO modulo;
    
    /**
     * Objeto de acesso aos dados de modulo.
     */
    private ModuloDAO moduloDao;
    
    /**
     * Construtor da classe.
     */
    public ModuloFacade() {
        this.moduloDao = new ModuloDAO();
    }
    
    /**
     * Getter da mensagem de retorno.
     * 
     * @return Mensagem de retorno.
     */
    public String getMessage() {
        String retorno = null;
        if(this.message == null || this.message.equals("")) {
            retorno = "&nbsp";
        } else {
            retorno = this.message;
        }
        return retorno;
    }

    /**
     * Setter da mensagem de retorno.
     * 
     * @param message Mensagem de retorno.
     */
    public void setMessage(String message) {
        this.message = message;
    }
    
    /**
     * Responsável por executar a operação selecionada pelo usuário.
     * 
     * @param req Requisição web do tipo HTTP.
     * @param resp Resposta da requisição HTTP.
     */
    public void operacao(HttpServletRequest req, HttpServletResponse resp) {
        String oper = req.getParameter("operacao");

        if(oper != null)
        {
            if (oper.equals("consultar")) {
                this.consultar(req, resp);
            }
            if (oper.equals("incluir")) {
                this.incluir(req, resp);
            }
            if (oper.equals("alterar")) {
                this.alterar(req, resp);
            }
            if (oper.equals("excluir")) {
                this.excluir(req, resp);
            }
            if (oper.equals("confirmar")) {
                this.confirmar(req, resp);
            }
        }
    }

    /**
     * Retorna o modulo.
     * 
     * @return Objeto modulo.
     */
    public ModuloVO getModulo() {
        return this.modulo;
    }
    
    /**
     * Seta o módulo.
     * 
     * @param modulo Objeto módulo.
     */
    public void setModulo(ModuloVO modulo) {
        this.modulo = modulo;
    }
    
    /**
     * Consultar um modulo.
     * 
     * @param req Requisição web do tipo HTTP.
     * @param resp Resposta da requisição HTTP.
     */
    public void consultar(HttpServletRequest req, HttpServletResponse resp) {
        String idModuloTmp = req.getParameter("idModulo");
        
        Integer idModulo = null;
        
        if(idModuloTmp == null || idModuloTmp.equals("")) {
            return;
        } else {
            idModulo = Integer.parseInt(idModuloTmp);
        }
        
        this.modulo = moduloDao.consultarPorId(idModulo);
    }

    /**
     * Incluir um modulo.
     * 
     * @param req Requisição web do tipo HTTP.
     * @param resp Resposta da requisição HTTP.
     */
    public void incluir(HttpServletRequest req, HttpServletResponse resp) {
        String noModulo = req.getParameter("noModulo");
        String dsModulo = req.getParameter("dsModulo");
        String dsChamada = req.getParameter("dsChamada");
        String stAtivo = req.getParameter("stAtivo");
        String cdModulo = req.getParameter("cdModulo");

        modulo = new ModuloVO();
        modulo.setNoModulo(noModulo);
        modulo.setDsModulo(dsModulo);
        modulo.setDsChamada(dsChamada);
        modulo.setStAtivo(stAtivo==null?"N":"S");
        modulo.setCdModulo((cdModulo==null || cdModulo.equals(""))?null:Integer.parseInt(cdModulo));
        
        String mensagem = null;
        
        if(noModulo == null || noModulo.equals("")) {
            mensagem = "Nome do modulo obrigatório.";
        }
        else if(dsModulo == null || dsModulo.equals("")) {
            mensagem = "Descrição do modulo obrigatória.";
        }
        else if(dsChamada == null || dsChamada.equals("")) {
            mensagem = "Chamada do modulo obrigatória.";
        }
        else {
            ModuloVO moduloCadastrado = moduloDao.consultarUmPorNomePorPai(modulo.getNoModulo(), modulo.getCdModulo());

            if(moduloCadastrado != null) {
                mensagem = "Modulo já cadastrado.";
            }
        }
        
        if(mensagem == null || mensagem.equals("")) {
            try {
                Transacao.iniciar();

                moduloDao.inserir(modulo);

                Transacao.efetivar();

                mensagem = "Modulo incluído com sucesso.";
            } catch (Exception ex) {
                Transacao.desfazer();

                mensagem = "Problema na inclusão do modulo: " + ex.getMessage();
            }
        } else {
            modulo = null;
        }
        
        this.message = mensagem;
    }

    /**
     * Alterar um modulo.
     * 
     * @param req Requisição web do tipo HTTP.
     * @param resp Resposta da requisição HTTP.
     */
    public void alterar(HttpServletRequest req, HttpServletResponse resp) {
        String idModulo = req.getParameter("idModulo");
        String noModulo = req.getParameter("noModulo");
        String dsModulo = req.getParameter("dsModulo");
        String dsChamada = req.getParameter("dsChamada");
        String stAtivo = req.getParameter("stAtivo");
        String cdModulo = req.getParameter("cdModulo");

        modulo = new ModuloVO();
        modulo.setIdModulo(Integer.parseInt(idModulo));
        modulo.setNoModulo(noModulo);
        modulo.setDsModulo(dsModulo);
        modulo.setDsChamada(dsChamada);
        modulo.setStAtivo(stAtivo==null?"N":"S");
        modulo.setCdModulo((cdModulo==null || cdModulo.equals(""))?null:Integer.parseInt(cdModulo));
        
        String mensagem = null;
        
        if(noModulo == null || noModulo.equals("")) {
            mensagem = "Nome do modulo obrigatório.";
        } else if(dsModulo == null || dsModulo.equals("")) {
            mensagem = "Descrição do modulo obrigatória.";
        } else if(dsChamada == null || dsChamada.equals("")) {
            mensagem = "Chamada do modulo obrigatória.";
        } else {
            ModuloVO moduloCadastrado = moduloDao.consultarUmPorIdDiferentePorNomePorPai(Integer.parseInt(idModulo), noModulo, modulo.getCdModulo());

            if(moduloCadastrado != null) {
                mensagem = "Nome já está sendo utilizado.";
            }
        }
        
        if(mensagem == null || mensagem.equals("")) {
            try {
                Transacao.iniciar();

                moduloDao.alterar(modulo);

                Transacao.efetivar();

                mensagem = "Modulo alterado com sucesso.";
            } catch (Exception ex) {
                Transacao.desfazer();

                mensagem = "Problema na alteração do modulo: " + ex.getMessage();
            }
        } else {
            modulo = null;
        }
        
        this.message = mensagem;
    }

    /**
     * Excluir um modulo.
     * 
     * @param req Requisição web do tipo HTTP.
     * @param resp Resposta da requisição HTTP.
     */
    public void excluir(HttpServletRequest req, HttpServletResponse resp) {
        String idModulo = req.getParameter("idModulo");

        modulo = new ModuloVO();
        modulo.setIdModulo(Integer.parseInt(idModulo));
        
        String mensagem = null;
        
        try {
            Transacao.iniciar();
            
            moduloDao.excluir(modulo);
            
            Transacao.efetivar();
            
            mensagem = "Modulo excluído com sucesso.";
        } catch (Exception ex) {
            Transacao.desfazer();
            
            mensagem = "Problema na exclusão do modulo: " + ex.getMessage();
        }
        
        this.modulo = null;
        
        this.message = mensagem;
    }
    
    /**
     * Confirmar a exclusão de modulo.
     * 
     * @param req Requisição web do tipo HTTP.
     * @param resp Resposta da requisição HTTP.
     */
    public void confirmar(HttpServletRequest req, HttpServletResponse resp) {
        String idModulo = req.getParameter("idModulo");
        String noModulo = req.getParameter("noModulo");

        modulo = new ModuloVO();
        modulo.setIdModulo(Integer.parseInt(idModulo));
        modulo.setNoModulo(noModulo);
    }

    /**
     * Retorna uma lista de modulos a partir de parâmetros da tela
     * 
     * @param req Requisição web do tipo HTTP.
     * @param resp Resposta da requisição HTTP.
     * @return objeto tabela com as informações necessárias
     */
    public TabelaHtml consultarModulos(HttpServletRequest req, HttpServletResponse resp) {
        String nome = req.getParameter("noModulo");
        
        if(nome != null && !nome.equals("")) {
            TabelaHtml tabela = new TabelaHtml();
            
            tabela.setCampoRetorno("idModulo");
            
            tabela.adicionarTitulo("Id");
            tabela.adicionarTamanho(0);
            tabela.adicionarTipo("Integer");
            tabela.adicionarStatus(false);

            tabela.adicionarTitulo("Nome");
            tabela.adicionarTamanho(80);
            tabela.adicionarTipo("String");
            tabela.adicionarStatus(true);
            
            tabela.gravarCampos();
            
            ModuloVO exemplo = new ModuloVO();
            
            exemplo.setNoModulo(nome);
            
            // Lista de modulos
            List<ModuloVO> modulos = moduloDao.consultarPorExemplo(exemplo);
            
            // Adiciona os valores de cada modulo nas listas de ids e nomes
            for(int i = 0; i < modulos.size(); i++) {
                tabela.adicionarRegistro(converterVoParaString(modulos.get(i)));
            }

            return tabela;
        }
        
        return null;
    }
    
    /**
     * Transforma os campos de um VO em uma lista de Strings
     * 
     * @return lista de strings com os valores em ordem
     */
    public List<String> converterVoParaString(ModuloVO modulo) {
        List<String> valores = new ArrayList<String>();
        
        valores.add(modulo.getIdModulo().toString());
        valores.add(modulo.getNoModulo());
        
        return valores;
    }

    /**
     * Consulta o id do modulo pelo nome dele.
     * 
     * @param nome Nome do modulo.
     * @return Id do modulo.
     */
    public Integer pegarIdModuloPorNome(String nome) {
        ModuloVO moduloConsultado = this.moduloDao.consultarUmPorNome(nome);
        
        return moduloConsultado.getIdModulo();
    }
    
    /**
     * Lista os modulos para o módulo de gestão de acordo com os acessos
     * do usuário.
     * 
     * @param idModulo Id do modulo.
     * @param idUsuario Id do usuário.
     * @return Html de construção do menu.
     */
    public String listarModulosPorModuloPaiPorUsuario(Integer idModuloPai, Integer idUsuario) {
        List<ModuloVO> listaModulo = moduloDao.consultarPorModuloPaiPorUsuario(idModuloPai, idUsuario);
        
        MontadorHtml montador = new MontadorHtml();
        
        return montador.montarMenuPrincipal(listaModulo);
    }

    /**
     * Monta o menu de acordo com os modulos que o usuário tem acesso e de 
     * acordo com o modulo pai.
     * 
     * @param idModuloPai Id do modulo pai.
     * @param idUsuario Id do usuário.
     * @return Html de construção do menu.
     */
    public String montarModulosPorModuloPaiPorUsuario(Integer idModuloPai, Integer idUsuario) {
        List<ModuloVO> listaModulo = moduloDao.consultarPorModuloPaiPorUsuario(idModuloPai, idUsuario);

        MontadorHtml montador = new MontadorHtml();

        return montador.montarMenuFuncionalidades(listaModulo, this.message);
    }
    
    /**
     * Monta a combo de módulos de acordo com a hierarquia de módulos
     * 
     * @param idModuloRaiz Módulo raiz da árvore hierárquica
     * @return List<List> lista hierárquica de módulos.
     */
    public List<List> montarComboModulos(Integer idModuloRaiz) {
        //Lista de strings da estrutura hierárquica
        List<List> listaHierarquica = new ArrayList<List>();
        
        // Lista de filhos do raiz
        List<ModuloVO> lista = new ArrayList<ModuloVO>();
        
        ModuloVO moduloAtual = null;
        
        // Modulo atual é o modulo raiz, caso seja nulo, módulo raiz é o raiz geral
        if(idModuloRaiz == null) {
            List<ModuloVO> listaRaiz = moduloDao.consultarPorModuloPaiOrdenadoPorId(idModuloRaiz);
            moduloAtual = listaRaiz.get(0);
        } else {
            moduloAtual = moduloDao.consultarPorId(idModuloRaiz);
        }
        
        // Inicia montagem da lista de VO filhos do módulo raiz
        lista.add(moduloAtual);
        
        int index = 0;

        Stack<ModuloVO> stackModuloAtual = new Stack<ModuloVO>();
        Stack<Integer> stackIndices = new Stack<Integer>();
        
        while(moduloAtual != null) {
            // Pega todos os filhos do módulo atual
            List<ModuloVO> filhosModuloAtual = moduloDao.consultarPorModuloPaiOrdenadoPorNome(moduloAtual.getIdModulo());
            List<ModuloVO> filhosItem = null;
            
            if(filhosModuloAtual.size() == 0 || index >= filhosModuloAtual.size()) {
                break;
            } else {
                filhosItem = moduloDao.consultarPorModuloPaiOrdenadoPorNome(filhosModuloAtual.get(index).getIdModulo());
                
                if(filhosItem.size() == 0) {
                    lista.add(filhosModuloAtual.get(index));
                    index++;
                    if(!stackIndices.empty() && index >= filhosModuloAtual.size()) {
                        index = stackIndices.pop() + 1;
                        moduloAtual = stackModuloAtual.pop();
                    }
                } else {
                    stackIndices.push(index);
                    stackModuloAtual.push(moduloAtual);
                    moduloAtual = filhosModuloAtual.get(index);
                    index = 0;
                    lista.add(moduloAtual);
                }
            }
        }
        
        // Monta a lista hierarquica com id, nome dos modulos e id do modulo pai
        for(int i = 0; i < lista.size(); i++) {
            List<String> registro = new ArrayList<String>();
            registro.add(lista.get(i).getIdModulo().toString());
            registro.add(lista.get(i).getNoModulo());
            registro.add(lista.get(i).getModuloPai()==null?null:lista.get(i).getModuloPai().getIdModulo().toString());
            listaHierarquica.add(registro);
        }
        
        return listaHierarquica;
    }

    /**
     * Monta a combo de módulos de acordo com a hierarquia de módulos
     * 
     * @return String HTML da combo.
     */
    public List<List> montarComboModulos() {
        return montarComboModulos(null);
    }
}
